#include "defines.h"
#include "Game.h"

Game::Game() :	STATE( GAME_STATE_INIT ),
				Board(),
				cursor( &Board ),
				timeKeep(),
				paused( false ),
				winner( 0 )
{
	gameScreen = new Screen;

	for( int i = 0; i < PLAYERS; ++i ) {
		capture_count[i] = 0;
	}

	//set all the input flags to false
	for( int i = 0; i < 10; i++ )
	{
		inputFlags[i] = false;
	}
	inputLock = false;
}

Game::~Game()
{
	delete gameScreen;
}

void Game::initGame()
{
	gameScreen->init();

	loadTitleScreen();
	cout << endl << "Press any key to begin... ";
	if (getch())
	{
		gameScreen->clearBuffer();
		Board.initializeBoard();
		cursor.addToBoard( &Board );
		Board.printBoard( gameScreen );
		gameScreen->displayBuffer();
		STATE = GAME_STATE_RUN;
	}
}

void Game::gameLoop()
{
	while ( STATE != GAME_STATE_EXIT )
	{
		//handling input
		getInput();
		
		switch( STATE )
		{
		case GAME_STATE_INIT:
			initGame();
			break;
		case GAME_STATE_RUN:
			//
			timeKeep.startClock();
				process();
			timeKeep.stopClock();
			break;

		case GAME_STATE_CONTINUE:
			//
			timeKeep.startClock();
				process();
			timeKeep.stopClock();
			break;

		case GAME_STATE_WINNER:
			//
			break;

		case GAME_STATE_STALEMATE:
			//
			break;

		case GAME_STATE_EXIT:

			break;
		default: break;
		}// end switch()
		
		if( timeKeep.chkTime() )
		{
			if( !paused ) {
				drawGame();
				#ifdef DEBUGMODE
					Sleep( DEBUGDELAY );
				#endif
			}
		}

	}//end while loop
	COORD endPos;
	endPos.X = EXIT_MSG_X;
	endPos.Y = EXIT_MSG_Y;
	SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE), endPos );
	cout << "Thank you for Playing!!!! \n\nExiting out of Pente now..........\n";

}//end gameLoop()
void Game::process()
{
	handleInput();
	//gameRules(); //This is in updateGame() which is called on a successful capture of a node
}

void Game::updateGame()
{
	//This is where piece captures happen
	int thatBelongsTo; //player that owns current node being checked
	int thisBelongsTo = Board.getActivePlayer();
	int unownedNode = -1; //defaults captured piece nodes to -1 (not owned by any player)  
	int numNodes = 0; //keeps track of the number of nodes owned by thatBelongsTo

	PenteBoardNode *startNode = Board.getNode( Board.RowCol( cursor.getX(), cursor.getY() ) );
	PenteBoardNode *onNode;

	int direction = 0;
	bool captureSuccess = false;

	while( direction < NUM_DIRECTIONS && captureSuccess != true ) {
		#ifdef DEBUGMODE
			printf( "Checking %d\nNodes owned is %d\n", direction, numNodes );
		#endif
		if( numNodes == 0 ) {
			#ifdef DEBUGMODE
				printf( "Starting at cursor node\n" );
			#endif
			if( startNode->hasNeighbor( direction ) ) {
				#ifdef DEBUGMODE
					printf( "Node found!\n" );
				#endif
				onNode = startNode->getDirectionalNodes( direction );

				if( onNode->pieceOnThisNode() ) {
					#ifdef DEBUGMODE
						printf( "piece found in direction %d\nOwned by %d\n", direction, onNode->getOwner() );
					#endif
					if( onNode->getOwner() != thisBelongsTo ) {
						thatBelongsTo = onNode->getOwner();
						numNodes = 1;
					}
				}
			}
		} else {
			if( numNodes == 1 ) {
				if( onNode->hasNeighbor( direction ) ) {
					onNode = onNode->getDirectionalNodes( direction );

					if( onNode->pieceOnThisNode() ) {
						if( onNode->getOwner() == thatBelongsTo ) {
							++numNodes;
						} else {
							numNodes = 0;
						}
					} else {
						numNodes = 0;
					}
				} else {
					numNodes = 0;
				}
			} else if( numNodes == 2 ) {
				if( onNode->hasNeighbor( direction ) ) {
					onNode = onNode->getDirectionalNodes( direction );

					if( onNode->pieceOnThisNode() ) {
						if( onNode->getOwner() == thisBelongsTo ) {
							captureSuccess = true;
							onNode = startNode;
							for( int i = 0; i < 2; ++i ) { //intentional use of a magic number
								onNode = onNode->getDirectionalNodes( direction );
								//onNode->changeOwner( thisBelongsTo );
								onNode->removePiece( unownedNode );
							}
						} else {
							numNodes = 0;
						}
					} else {
						numNodes = 0;
					}
				} else {
					numNodes = 0;
				}
			}
		}

		if( numNodes == 0 ) {	//Wow... the first time a while loop was necessary instead of for...
			++direction;		// Although this could probably be ( numNodes == 0 ? ++direction : direction = direction ) in a for loop :p But that's gross
		}
	}

	if( captureSuccess == true ) {
		++capture_count[thisBelongsTo];
	}


	gameRules();
}

// this is the update draw function
void Game::drawGame()
{
	COORD cursorPos;
	int captureX = BOARD_X + PenteBoard::getWidth() + 2;
	char plyrStr[15];
	char capStr[15];

	gameScreen->clearBuffer();

	Board.printBoard( gameScreen );
	cursor.drawCursor( gameScreen );

	cursorPos = gameScreen->displayAt( captureX, BOARD_Y, "Captures:" ); //display capture counts
	++cursorPos.Y;
	++cursorPos.Y;
	for( int i = 0; i < PLAYERS; ++i ) {
        cursorPos = gameScreen->displayAt( captureX, cursorPos.Y, "Player " );
		cursorPos = gameScreen->displayAt( cursorPos.X, cursorPos.Y, itoa( i + 1, plyrStr, 10 ) );
		cursorPos = gameScreen->displayAt( cursorPos.X, cursorPos.Y, ": " );
		cursorPos = gameScreen->displayAt( cursorPos.X, cursorPos.Y, itoa( capture_count[i], capStr, 10 ) );
		++cursorPos.Y;
		cursorPos.X = captureX;
	}
	
	gameScreen->displayBuffer();
}
void Game::getInput()
{
	char input = '\0';//temporary input variable 

	if( _kbhit() )
	{
		inputLock = true;
		input = _getch();
		if( !paused ) { //These inputs should not be accepted if the game is paused
			switch(input)
			{
			case 'W':
			case 'w':
				inputFlags[ INPUT_W_KEY ] = true;
				break;
			case 'A':
			case 'a':
				inputFlags[ INPUT_A_KEY ] = true;
				break;
			case 'S':
			case 's':
				inputFlags[ INPUT_S_KEY ] = true;
				break;
			case 'D':
			case 'd':
				inputFlags[ INPUT_D_KEY ] = true;
				break;
			case 10: // line feed
			case 13: // return key
				inputFlags[ INPUT_ENTER_KEY ] = true;
				break;
			}
		}

		switch( input ) {
			case 'P':
			case 'p':
				inputFlags[ INPUT_P_KEY ] = true;
				#ifdef DEBUGMODE
					printf( "'p' key hit!\n" );
				#endif
				break;
			case 'R':
			case 'r':
				inputFlags[ INPUT_R_KEY ] = true;
				break;
			case 27: // escape key
				inputFlags[ INPUT_ESC_KEY ] = true;
				break;
			default: break;
		}//end switch()
	}
}
void Game::handleInput()
{
	if( inputFlags[ INPUT_W_KEY ] ) //move cursor up
	{
		cursor.moveCursor( NORTH );
		inputFlags[ INPUT_W_KEY ] = false;
	}
		
	if( inputFlags[ INPUT_A_KEY ] ) // move cursor left
	{
		cursor.moveCursor( WEST );
		inputFlags[ INPUT_A_KEY ] = false;
	}

	if( inputFlags[ INPUT_S_KEY ] ) // move cursor down
	{

		inputFlags[ INPUT_S_KEY ] = false;
		cursor.moveCursor( SOUTH );
	}
	if( inputFlags[ INPUT_D_KEY ] ) // move cursor right
	{	
		inputFlags[ INPUT_D_KEY ] = false;
		cursor.moveCursor( EAST );
	}
	if( inputFlags[ INPUT_ENTER_KEY ] )
	{
		// line feed (char 10?)
		// return key (char 13?)
		// all these keys will cause the game to update when the piece gets set
		PenteBoardNode *node = Board.getNode( Board.RowCol( cursor.getX(), cursor.getY() ) );
		if( node->captureNode( Board.getActivePlayer() ) ) {
            updateGame();
			Board.switchActivePlayer();
		}

		inputFlags[ INPUT_ENTER_KEY ] = false;
	}

	if( inputFlags[ INPUT_P_KEY ] ) // Pause now
	{
		#ifdef DEBUGMODE
			printf( "pause button hit!\n" );
		#endif

		paused = !paused;
		inputFlags[ INPUT_P_KEY ] = false;
	}
	if( inputFlags[ INPUT_R_KEY ] )
	{
		//add restart functionality here...
		inputFlags[ INPUT_R_KEY ] = false;
	}

	if( inputFlags[ INPUT_ESC_KEY ] ) // escape key
	{	
		STATE = GAME_STATE_EXIT;
		inputFlags[ INPUT_ESC_KEY ] = false;
	}	
}

void Game::loadTitleScreen()
{
	char character;
	ifstream infile;
	infile.open("../../titlescreen.txt");
	if (!(infile.is_open()))
		cout << "Error in loading Title Screen from file" << endl;
	else
	{
		while (!(infile.eof()))
		{
			infile.get(character);
			cout << character;
		}
	}
}

void Game::gameRules()
{
	int currentPlayer = Board.getActivePlayer();
	int numNodes = 1; //For the node that was just captured
	int direction = 0;
	int otherDirection;
	PenteBoardNode *startNode = Board.getNodeAt( cursor.getX(), cursor.getY() );
	PenteBoardNode *onNode = startNode;

	for( int i = 0; i < PLAYERS; ++i ) { //Check capture count win
		if( capture_count[i] >= CAPTURES_TO_WIN ) {
			winner = i;
			gameOver();
			return;
		}
	}

	//check line win
	while( direction < NUM_DIRECTIONS ) { //redundant, but necessary to check all directions on a wall node (without doubling this code)
		if( onNode->hasNeighbor( direction ) ) {
			onNode = onNode->getDirectionalNodes( direction );
			if( onNode->pieceOnThisNode() && onNode->getOwner() == currentPlayer ) {
				++numNodes;
			} else { //try the other direction
				onNode = startNode;
				otherDirection = ( direction + NUM_DIRECTIONS / 2 ) % NUM_DIRECTIONS;
				
				while( onNode->hasNeighbor( otherDirection ) ) {
					onNode = onNode->getDirectionalNodes( otherDirection );
					if( onNode->pieceOnThisNode() && onNode->getOwner() == currentPlayer ) {
						++numNodes;
					} else {
						break;
					}
				}
			}
		}
		if( numNodes >= LINE_WIN_SIZE ) {
			winner = currentPlayer;
			gameOver();
			break;
		} else {
			numNodes = 1;
			onNode = startNode;
			++direction;
		}
	}
}

void Game::gameOver() {
	//paused = true;
	COORD congratPos;
	congratPos.X = CONGRATS_X;
	congratPos.Y = CONGRATS_Y;
	#ifdef DEBUGMODE
		printf( "Game Over!!\nWinner is player %d!\n", winner );
	#endif
		gameScreen->clearScreen();
		SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE), congratPos );
		loadVictoryFile();
		printf( "Game Over!!\nWinner is player %d!\n", winner + 1 );
		paused = true;
	//drawGame();
}

void Game::loadVictoryFile()
{
	char character;
	ifstream infile;
	infile.open("../../victoryscreen.txt");
	if (!(infile.is_open()))
		cout << "Error in loading Victory File" << endl;
	else
	{
		while (!(infile.eof()))
		{
			infile.get(character);
			cout << character;
		}
	}
}